package db4oClass.daoClass;

import general.appClass.StatisticApp;
import general.dbClass.*;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.Predicate;

public class Db4oDaoGet {
	/**
	 * get next available photo'id from database
	 * @param conn			connection with database
	 * @return				next available photo'id
	 */
	@SuppressWarnings("serial")
	public static int nextPhotoId(ObjectContainer conn) {
		DBId id = null;
		
		ObjectSet<DBId> objectset = conn.query(new Predicate<DBId>() {
			public boolean match(DBId id) {
				return true;
			}
		});
		
		if(objectset.isEmpty()) {
			id = new DBId();
		}else {
			id = objectset.next();
		}
		
		int ret = id.getPhotoId();
		
		id.setPhotoId(ret+1);
		conn.store(id);
		conn.commit();
		
		return ret;
	}
	
	/**
	 * get next available category's id from database
	 * @param conn			connection with database
	 * @return				next available category's id
	 */
	@SuppressWarnings("serial")
	public static int nextCategoryId(ObjectContainer conn) {
		DBId id = null;
		
		ObjectSet<DBId> objectset = conn.query(new Predicate<DBId>() {
			public boolean match(DBId id) {
				return true;
			}
		});
		
		if(objectset.isEmpty()) {
			id = new DBId();
		}else {
			id = objectset.next();
		}
		
		int ret = id.getCategoryId();
		
		id.setCategoryId(ret+1);
		
		conn.store(id);
		conn.commit();
		
		return ret;
	}
	
	/**
	 * get next available tag's id from database
	 * @param conn			connection with database
	 * @return				next available tag's id
	 */
	@SuppressWarnings("serial")
	public static int nextTagId(ObjectContainer conn) {
		DBId id = null;
		
		ObjectSet<DBId> objectset = conn.query(new Predicate<DBId>() {
			public boolean match(DBId id) {
				return true;
			}
		});
		
		if(objectset.isEmpty()) {
			id = new DBId();
		}else {
			id = objectset.next();
		}
	
		int ret = id.getTagId();
		
		id.setTagId(ret+1);
		conn.store(id);
		conn.commit();
		
		return ret;
	}

	
	/**
	 * get all categories from database
	 * @param conn			connection with database
	 * @return				all categories
	 */
	@SuppressWarnings("serial")
	public static ArrayList<DBCategory> getAllCategories(ObjectContainer conn) {
		ObjectSet<DBCategory> objectset = conn.query(new Predicate<DBCategory>() {
			public boolean match(DBCategory category) {
				return true;
			}
		});
		
		ArrayList<DBCategory> categories = new ArrayList<DBCategory>();
		
		while(objectset.hasNext()) {
			DBCategory tmp = objectset.next();
			categories.add(tmp);
		}
		
		return categories;
	}
	
	
	/**
	 * get all tags from database
	 * @param conn		connection with database	
	 * @return			all tags
	 */
	@SuppressWarnings("serial")
	public static ArrayList<DBKeyword> getAllKeywords(ObjectContainer conn) {
		ObjectSet<DBKeyword> objectset = conn.query(new Predicate<DBKeyword>() {
			public boolean match(DBKeyword tag) {
				return true;
			}
		});
		
		ArrayList<DBKeyword> tags = new ArrayList<DBKeyword>();
		
		while(objectset.hasNext()) {
			DBKeyword tmp = objectset.next();
			tags.add(tmp);
		}
		
		return tags;
	}
	
	/**
	 * get all the photo's id from database
	 * @param conn		connection with database
	 * @return			all the photo's id;
	 */
	@SuppressWarnings("serial")
	public static ArrayList<DBPicInfo> getAllPhoto(ObjectContainer conn) {
		ObjectSet<DBPicInfo> objectset = conn.query(new Predicate<DBPicInfo>() {
			public boolean match(DBPicInfo photo) {
				return true;
			}
		});
		
		ArrayList<DBPicInfo> ret = new ArrayList<DBPicInfo>();
		
		while(objectset.hasNext()) {
			DBPicInfo tmp = objectset.next();
			ret.add(tmp);
		}
		
		return ret;
	}
	
	/**
	 * 
	 * @param container
	 * @param category
	 * @return
	 */
	@SuppressWarnings("serial")
	public static ArrayList<DBPicInfo> getPhotosByCategory(ObjectContainer container,final DBCategory category) {
		ObjectSet<DBPicInfo> objectset = container.query(new Predicate<DBPicInfo>() {	
			public boolean match(DBPicInfo photo) {
				ArrayList<DBCategory> categories = photo.getCategories();
				for(int i=0;i<categories.size();i++) {
					if(categories.get(i).getNr() == category.getNr())
						return true;
				}
				return false;
			}
		});
		
		ArrayList<DBPicInfo> ret = new ArrayList<DBPicInfo>();
		
		while(objectset.hasNext()) {
			DBPicInfo tmp = objectset.next();
			ret.add(tmp);
		}
		
		return ret;
	}
	
	/**
	 * get photo from database by photo's id
	 * @param container		connection with database
	 * @param photoId		photo's id
	 * @return				photo
	 */
	@SuppressWarnings("serial")
	public static DBPicInfo getPhotoInfoById(ObjectContainer container, final int photoId) {
		ObjectSet<DBPicInfo> objectset = container.query(new Predicate<DBPicInfo>() {
			public boolean match(DBPicInfo photo) {
				return photo.getNr() == photoId;
			}
		});
		
		if (objectset.isEmpty())
			return null;
		
		else return objectset.next();
	}
	
	/**
	 * get full size of image from db4o database
	 * @param container			object container
	 * @param photoId			image's id
	 * @return					
	 */
	@SuppressWarnings("serial")
	public static DBPicData getPhotoDataById(ObjectContainer container,final int photoId) {
		ObjectSet<DBPicData> objectset = container.query(new Predicate<DBPicData>(){
			public boolean match(DBPicData photo) {
				return photo.getNr() == photoId;
			}
		});
		
		if(objectset.isEmpty())
			return null;
		else
			return objectset.next();
	}
	
	/**
	 * get thumbnail's data from database by photo's id
	 * @param conn			connection with database
	 * @param photoId		photo's id
	 * @return				data as byte array
	 */
	@SuppressWarnings("serial")
	public static DBThumbData getThumbByPhotoId(ObjectContainer conn,final int photoId) {
		DBThumbData ret = null;
		
		long begin = new Date().getTime();
		
		ObjectSet<DBThumbData> objectset = conn.query(new Predicate<DBThumbData>(){
			public boolean match(DBThumbData thumb) {
				return thumb.getNr() == photoId;
			}
		});
		
		if(objectset.isEmpty())
			ret = null;
		else
			ret = objectset.next();
		
		long end = new Date().getTime();
		long time = end - begin;
		
		StatisticApp.query("thumb", "db4o", ret.getSize(), time, 1);
		
		return ret;
	}
	
	
	/**
	 * get category from database by category's id
	 * @param conn			connection with database
	 * @param categoryId	category's id
	 * @return				category
	 */
	@SuppressWarnings("serial")
	public static DBCategory getCategoryById(ObjectContainer conn,final int categoryId) {
		ObjectSet<DBCategory> objectset = conn.query(new Predicate<DBCategory>() {
			public boolean match(DBCategory category) {
				return category.getNr() == categoryId;
			}
		});
		
		if(objectset.isEmpty())
			return null;
		
		else return objectset.next();
	}
	
	
	/**
	 * get tag from database by tag's id
	 * @param conn		connection with database
	 * @param tagId		tag's id
	 * @return			tag
	 */
	@SuppressWarnings("serial")
	public static DBKeyword getTagById(ObjectContainer conn,final int tagId) {
		ObjectSet<DBKeyword> objectset = conn.query(new Predicate<DBKeyword>() {
			public boolean match(DBKeyword tag) {
				return tag.getNr() == tagId;
			}
		});
		
		if(objectset.isEmpty())
			return null;
		
		else return objectset.next();
	}
	
	/**
	 * get category by name
	 * @param conn		connection with database
	 * @param name		category's name
	 * @return			category
	 */
	@SuppressWarnings("serial")
	public static DBCategory getCategoryByName(ObjectContainer conn,final String name) {
		ObjectSet<DBCategory> objectset = conn.query(new Predicate<DBCategory>() {
			public boolean match(DBCategory category) {
				return category.getName().equals(name);
			}
		});
		
		if(objectset.isEmpty())
			return null;
		
		else return objectset.next();
	}
	
	/**
	 * get tag by name
	 * @param container		connection with database
	 * @param name			tag's name
	 * @return				tag
	 */
	@SuppressWarnings("serial")
	public static DBKeyword getTagByName(ObjectContainer container,final String name) {
		ObjectSet<DBKeyword> objectset = container.query(new Predicate<DBKeyword>() {
			public boolean match(DBKeyword keyword) {
				return keyword.getWord().equals(name);
			}
		});
		
		if(objectset.isEmpty())
			return null;
		
		else return objectset.next();	
	}
	
	/**
	 * 
	 * @param container
	 * @param name
	 * @return
	 */
	@SuppressWarnings("serial")
	public static ArrayList<String> getAllExifInfoByName(ObjectContainer container,final String name) {
		ArrayList<String> ret = new ArrayList<String>();
		
		ObjectSet<DBPicInfo> objectset = container.query(new Predicate<DBPicInfo>() {
			public boolean match(DBPicInfo photo) {
				return true;
			}
		});
		
		if(objectset.isEmpty())
			return ret;
		
		while(objectset.hasNext()) {
			DBPicInfo 	photo 	= objectset.next();
			DBExif		exif 	= photo.getExif();
			String		tmp		= "";
			boolean		has		= false;
			
			if(name.equals("format"))
				tmp = exif.getOrietation();
			else if(name.equals("expousureProgram"))
				tmp = exif.getExposureProgram();
			else if(name.equals("exposureMode"))
				tmp = exif.getExposureMode();
			else if(name.equals("exposureTime"))
				tmp = exif.getExposureTime();
			else if(name.equals("colorSpace"))
				tmp = exif.getColorSpace();
			else if(name.equals("fnumber"))
				tmp = exif.getFnumber();
			else if(name.equals("make"))
				tmp = exif.getMake();
			else if(name.equals("model"))
				tmp = exif.getModel();
			
			if(tmp==null || tmp.equals(""))
				continue;
			
			for(int i=0;i<ret.size();i++) {
				if(ret.get(i).equals(tmp)) {
					has = true;
					break;
				}
			}
			
			if(!has)
				ret.add(tmp);
		}
		
		return ret;
	}

	/**
	 * get photos by keyword
	 * @param container
	 * @param keyword
	 * @return
	 */
	@SuppressWarnings("serial")
	public static ArrayList<DBPicInfo> getPhotosByKeyword(ObjectContainer container, final DBKeyword keyword) {
		ObjectSet<DBPicInfo> objectset = container.query(new Predicate<DBPicInfo>() {	
			public boolean match(DBPicInfo photo) {
				ArrayList<DBKeyword> keywords = photo.getKeywords();
				for(int i=0;i<keywords.size();i++) {
					if(keywords.get(i).getNr() == keyword.getNr())
						return true;
				}
				return false;
			}
		});
		
		ArrayList<DBPicInfo> ret = new ArrayList<DBPicInfo>();
		
		while(objectset.hasNext()) {
			DBPicInfo tmp = objectset.next();
			ret.add(tmp);
		}
		
		return ret;
	}

	@SuppressWarnings("serial")
	public static ArrayList<DBPicInfo> getPhotosByExtraSearch(ObjectContainer container, final SearchTerm[][] terms) {
		ArrayList<DBPicInfo> ret = new ArrayList<DBPicInfo>();
		
		ObjectSet<DBPicInfo> objectset = container.query(new Predicate<DBPicInfo>() {	
			public boolean match(DBPicInfo photo) {
				boolean all = false;
				
				for(int i=0;i<4;i++) {
					boolean row = true;
					boolean rowValid = false;
					
					for(int j=0;j<4;j++) {				
						if(terms[i][j] != null) {
							rowValid = true;
							
							String name 	= terms[i][j].getName();
							String compare	= terms[i][j].getCompare();
							String value	= terms[i][j].getValue();
							
							if(name.equals("kwnr")) {
								ArrayList<DBKeyword> keywords = photo.getKeywords();
								boolean tmp = false;
								for(int x=0;x < keywords.size();x++) {
									if(keywords.get(x).getNr()==Integer.parseInt(value)) {
										tmp = true;
										break;
									}
								}
								
								if(compare.equals("=")) {
									row = row & tmp;
								}else {
									row = row & !tmp;
								}
							}else if(name.equals("ktnr")) {
								ArrayList<DBCategory> categories = photo.getCategories();
								boolean tmp =false;
								for(int x=0;x < categories.size();x++) {
									if(categories.get(x).getNr()==Integer.parseInt(value)){
										tmp = true;
										break;
									}
								}
								
								if(compare.equals("=")) {
									row = row & tmp;
								}else {
									row = row & !tmp;
								}
							}else if(name.equals("imgHeight")) {
								try {
									int tmp = Integer.parseInt(value);
									int x = photo.getExif().getImgHeightValue();
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x >= tmp;
									else if(compare.equals("<="))
										row = row & x <= tmp;
									else if(compare.equals("!="))
										row = row & x != tmp;
								}catch(Exception e) {
								}
							}else if(name.equals("imgWidth")) {
								try {
									int tmp = Integer.parseInt(value);
									int x = photo.getExif().getImgWidthValue();
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x >= tmp;
									else if(compare.equals("<="))
										row = row & x <= tmp;
									else if(compare.equals("!="))
										row = row & x != tmp;
								}catch(Exception e) {
								}
							}else if(name.equals("exposureTime")) {
								try {
									float tmp;
									float x = photo.getExif().getExposureTimeValue();
									
									if(x == 0.0f) {
										row = row & false;
										break;
									}
									
									value = value.replace(" sec", "");
									if (value.indexOf('/') >= 0) {
										tmp = (float) (1.0 * Integer.parseInt(value.split("/")[0]) / Integer.parseInt(value.split("/")[1]));
									} else {
										tmp = (float) (1.0 * Float.parseFloat(value));
									}
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x >= tmp;
									else if(compare.equals("<="))
										row = row & x <= tmp;
									else if(compare.equals("!="))
										row = row & x != tmp;
								}catch(Exception e) {
									row = row & false;
								}
							}else if(name.equals("fnumber")) {
								try {
									float tmp = Float.parseFloat(value.replace("F", "").replace(",", "."));
									float x = photo.getExif().getFnumberValue();
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x >= tmp;
									else if(compare.equals("<="))
										row = row & x <= tmp;
									else if(compare.equals("!="))
										row = row & x != tmp;
								}catch(Exception e) {
								}
							}else if(name.equals("exposureProgram")) {
								if(compare.equals("="))
									row = row & photo.getExif().getExposureProgram().equals(value);
								else
									row = row & !photo.getExif().getExposureProgram().equals(value);
							}else if(name.equals("timeDigitized")) {
								try {
									SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
									Date 	tmp = sdf.parse(value);
									Date 	x = photo.getExif().getTimeDigitizedValue();
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x.after(tmp);
									else if(compare.equals("<="))
										row = row & x.before(tmp);
									else if(compare.equals("!="))
										row = row & x != tmp;	
								}catch(Exception e) {
									e.printStackTrace();
									row = row & false;
								}
							}else if(name.equals("timeOriginal")) {
								try {
									SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
									Date 	tmp = sdf.parse(value);
									Date 	x = photo.getExif().getTimeOriginalValue();
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x.after(tmp);
									else if(compare.equals("<="))
										row = row & x.before(tmp);
									else if(compare.equals("!="))
										row = row & x != tmp;	
								}catch(Exception e) {
									e.printStackTrace();
									row = row & false;
								}
							}else if(name.equals("colorSpace")) {
								if(compare.equals("="))
									row = row & photo.getExif().getColorSpace().equals(value);
								else
									row = row & !photo.getExif().getColorSpace().equals(value);
							}else if(name.equals("exifImgWidth")) {
								try {
									int tmp = Integer.parseInt(value);
									int x = photo.getExif().getExifImgWidthValue();
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x >= tmp;
									else if(compare.equals("<="))
										row = row & x <= tmp;
									else if(compare.equals("!="))
										row = row & x != tmp;
								}catch(Exception e) {
								}
							}else if(name.equals("exifImgHeight")) {
								try {
									int tmp = Integer.parseInt(value);
									int x = photo.getExif().getExifImgHeightValue();
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x >= tmp;
									else if(compare.equals("<="))
										row = row & x <= tmp;
									else if(compare.equals("!="))
										row = row & x != tmp;
								}catch(Exception e) {
								}
							}else if(name.equals("exposureMode")) {
								if(compare.equals("="))
									row = row & photo.getExif().getExposureMode().equals(value);
								else
									row = row & !photo.getExif().getExposureMode().equals(value);
							}else if(name.equals("make")) {
								if(compare.equals("="))
									row = row & photo.getExif().getMake().equals(value);
								else
									row = row & !photo.getExif().getMake().equals(value);
							}else if(name.equals("model")) {
								if(compare.equals("="))
									row = row & photo.getExif().getModel().equals(value);
								else
									row = row & !photo.getExif().getModel().equals(value);
							}else if(name.equals("orientation")) {
								if(compare.equals("="))
									row = row & photo.getExif().getOrietation().equals(value);
								else
									row = row & !photo.getExif().getOrietation().equals(value);
							}else if(name.equals("xResolution")) {
								try {
									int tmp = Integer.parseInt(value);
									int x = photo.getExif().getxResolutionValue();
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x >= tmp;
									else if(compare.equals("<="))
										row = row & x <= tmp;
									else if(compare.equals("!="))
										row = row & x != tmp;
								}catch(Exception e) {
								}
							}else if(name.equals("yResolution")) {
								try {
									int tmp = Integer.parseInt(value);
									int x = photo.getExif().getyResolutionValue();
									
									if(compare.equals("="))
										row = row & x == tmp;
									else if(compare.equals(">="))
										row = row & x >= tmp;
									else if(compare.equals("<="))
										row = row & x <= tmp;
									else if(compare.equals("!="))
										row = row & x != tmp;
								}catch(Exception e) {
								}
							}
						}
					}
					all = all | (row & rowValid);
				}
				return all;
			}
		});
		
		while(objectset.hasNext()) {
			DBPicInfo tmp = objectset.next();
			ret.add(tmp);
		}
		
		return ret;
	}

}
